/*
 * Game.cpp
 *
 *  Created on: Nov 15, 2012
 *      Author: lucas
 */

#include "Game.h"
#include "EggFactory.h"
#include "Pig.h"
#include "Egg.h"
#include "Level.h"
#include "Match.h"
#include "Player.h"
#include "Surface.h"
#include "VisibleElement.h"
#include "Vector2D.h"
#include "WhiteEgg.h"
#include <iostream>
#include <unistd.h>
Game::Game(Level* l, Player* p) : level(l), bg(*this), eg(*this), gameCV(gameMutex), ended(false), won(false)  {
	loadLevel(p);
}


void Game::play() {
	Egg* egg;
	while (playingtime < finishtime) {

		while (!freePigsQueue.empty()) {
			if (players.size() != 0)	//si no quedan jugadores, termino el juego
				pause();
			else {
				ended = true;
				return;
			}
		}
		bg.generateBird();
		while (!(eggsQueue.empty())) {
			egg = eggsQueue.pop();
			addVisibleElement(egg);
		}
		pe.run(DELTAT);
		deleteDisposableObjects();
		if (!checkPigsHealth()) {
			ended = true;
			generateMatch();
			sleep(5);
			return;
		}
		generateMatch();
		//chequear vida de chanchos, si estan muertos salir del juego
		usleep(DELTATUSEC);
		++playingtime;
	}
	ended = true;
	won = true;

}

void Game::ejecutar() {

	this->play();

}

bool Game::addPlayer(Player* player) {
	Lock l(gameMutex);
	Pig* pig;
	if (!freePigsQueue.empty()) {
		pig = freePigsQueue.pop();
		players[player] = pig;
		player->setGame(this);
		player->setPig(pig);
		if (players.size() > 1)
			gameCV.signal();
		return true;
	}
	return false;
}



int Game::getPlayers() {
	Lock l(gameMutex);
	return players.size();
}

eggTypes Game::getNextEgg() {
	return eg.generateEgg();
}

void Game::addVisibleElement(VisibleElement* e) {
	entities.push_back(e);
	pe.add(*e);
}

void Game::deleteDisposableObjects() {
	std::list<VisibleElement*>::iterator it;
	for (it = entities.begin(); it != entities.end(); ++it) {
		if (((*it)->isDisposable()) || isOutOfRange(*it)) {
			pe.remove(**it);
			delete *it;
			it = entities.erase(it);
		}
	}
}

bool Game::isOutOfRange(VisibleElement* e) {
	double x;
	double y;
	x = e->getX();
	y = e->getY();
	if (x < 0 || x > (level->getWidth() - IMAGE_WIDTH) || y > (level->getHeight() - IMAGE_HEIGHT ))
		return true;
	return false;
}

void Game::generateMatch() {
	Match *m, *aux;
	VisibleElement *e;
	std::list<VisibleElement*>::iterator itVE;
	std::map<Player*, Pig*>::iterator itM;
	m = new Match();
	for (itVE = entities.begin(); itVE != entities.end(); ++itVE) {
		e = (*itVE)->makeCopy();
		m->add(e);
	}
	for (itM = players.begin(); itM != players.end(); ++itM) {
		e = itM->second->makeCopy();
		m->add(e);
	}
	Lock l(matchMutex);
	aux = match;
	match = m;
	delete aux;
}

Match* Game::getMatch() {
	Lock l(matchMutex);
	return match;
}

Game::~Game() {
}

void Game::pause() {
	gameCV.wait();
}

void Game::loadLevel(Player* p) {
	std::list<BirdShootingLine*> lbsl;
	std::list<BirdShootingLine*>::iterator itBsl;
	std::list<VisibleElement*>::iterator itV;
	std::list<Pig*> lpig;
	std::list<Pig*>::iterator itP;
	lbsl = level->getBirdShootingLines();
	for (itBsl = lbsl.begin(); itBsl != lbsl.end(); ++itBsl) {
		bg.addBirdShootingLine(*itBsl);
	}
	entities = level->getVisibleElements();
	for (itV = entities.begin(); itV != entities.end(); ++itV) {
		pe.add(**itV);
	}
	lpig = level->getPigs();

	for (itP = lpig.begin(); itP != lpig.end(); ++itP) {
		freePigsQueue.push(*itP);
		pe.add(**itP);
	}
	surface = level->getSurface();
	addPlayer(p);
	playingtime = 0;
	finishtime = level->getLevelTime() / DELTAT;

}


void Game::addEgg(eggTypes e, double x, double y, Vector2D speed) {
	Egg* egg;
	egg = EggFactory::createEgg(e, x, y, speed);
	eggsQueue.push(egg);
}

void Game::addPig(Pig* p) {
	freePigsQueue.push(p);
}

void Game::removePlayer(Player* player) {
	std::map<Player*,Pig*>::iterator it;
	Lock l(gameMutex);
	it = players.find(player);
	freePigsQueue.push(it->second);
	players.erase(player);
}

bool Game::gameEnded() {
	return ended;
}

bool Game::gameWon() {
	return won;
}

bool Game::checkPigsHealth() {
	std::map<Player*, Pig*>::iterator it;
	bool ret;
	ret = false;
	for (it = players.begin(); it != players.end(); ++it) {
		if (it->second->getHitPoints() <= 0) {
			it->second->setImagePath("cerdito_rojo.png");
		}
		else
			ret = true;
	}
	return ret;
}






